package com.example.library.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.library.common.ResultCode;
import com.example.library.dto.BaseQueryRequest;
import com.example.library.entity.Book;
import com.example.library.entity.BorrowRecord;
import com.example.library.entity.User;
import com.example.library.mapper.BorrowRecordMapper;
import com.example.library.service.BookService;
import com.example.library.service.BorrowRecordService;
import com.example.library.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map;

/**
 * 借阅记录服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class BorrowRecordServiceImpl extends ServiceImpl<BorrowRecordMapper, BorrowRecord> implements BorrowRecordService {

    private final BorrowRecordMapper borrowRecordMapper;
    private final UserService userService;
    private final BookService bookService;

    @Value("${library.borrow.max-books-per-user:5}")
    private Integer maxBorrowBooks;

    @Value("${library.borrow.default-borrow-days:30}")
    private Integer defaultBorrowDays;

    @Value("${library.borrow.fine-per-day:1.0}")
    private BigDecimal finePerDay;

    @Override
    public IPage<BorrowRecord> getBorrowRecordPage(BaseQueryRequest queryRequest) {
        Page<BorrowRecord> page = new Page<>(queryRequest.getCurrent(), queryRequest.getSize());
        return borrowRecordMapper.selectBorrowRecordPage(page,
                null,
                null,
                null,
                null,
                null);
    }

    @Override
    public IPage<BorrowRecord> getUserBorrowRecords(Long userId, BaseQueryRequest queryRequest) {
        Page<BorrowRecord> page = new Page<>(queryRequest.getCurrent(), queryRequest.getSize());
        return borrowRecordMapper.selectBorrowRecordPage(page,
                userId,
                null,
                null,
                null,
                null);
    }

    @Override
    public IPage<BorrowRecord> getBookBorrowRecords(Long bookId, BaseQueryRequest queryRequest) {
        Page<BorrowRecord> page = new Page<>(queryRequest.getCurrent(), queryRequest.getSize());
        return borrowRecordMapper.selectBorrowRecordPage(page,
                null,
                bookId,
                null,
                null,
                null);
    }

    @Override
    public List<BorrowRecord> getCurrentBorrowedBooks(Long userId) {
        return borrowRecordMapper.selectCurrentBorrowsByUser(userId);
    }

    @Override
    public IPage<BorrowRecord> getOverdueRecords(BaseQueryRequest queryRequest) {
        Page<BorrowRecord> page = new Page<>(queryRequest.getCurrent(), queryRequest.getSize());
        List<BorrowRecord> records = borrowRecordMapper.selectOverdueRecords();
        // 手动分页处理
        int start = (int) ((queryRequest.getCurrent() - 1) * queryRequest.getSize());
        int end = Math.min(start + queryRequest.getSize().intValue(), records.size());
        List<BorrowRecord> pageRecords = start < records.size() ? records.subList(start, end) : new ArrayList<>();
        page.setRecords(pageRecords);
        page.setTotal(records.size());
        return page;
    }

    @Override
    public IPage<BorrowRecord> getDueSoonRecords(Integer days, BaseQueryRequest queryRequest) {
        Page<BorrowRecord> page = new Page<>(queryRequest.getCurrent(), queryRequest.getSize());
        List<BorrowRecord> records = borrowRecordMapper.selectDueSoonRecords(days);
        // 手动分页处理
        int start = (int) ((queryRequest.getCurrent() - 1) * queryRequest.getSize());
        int end = Math.min(start + queryRequest.getSize().intValue(), records.size());
        List<BorrowRecord> pageRecords = start < records.size() ? records.subList(start, end) : new ArrayList<>();
        page.setRecords(pageRecords);
        page.setTotal(records.size());
        return page;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BorrowRecord borrowBook(Long userId, Long bookId, Integer borrowDays) {
        // 检查用户是否存在
        User user = userService.getById(userId);
        if (user == null) {
            throw new RuntimeException(ResultCode.USER_NOT_FOUND.getMessage());
        }

        // 检查用户状态
        if (!user.isEnabled()) {
            throw new RuntimeException(ResultCode.USER_DISABLED.getMessage());
        }

        // 检查图书是否存在
        Book book = bookService.getById(bookId);
        if (book == null) {
            throw new RuntimeException(ResultCode.BOOK_NOT_FOUND.getMessage());
        }

        // 检查图书状态
        if (!book.isOnline()) {
            throw new RuntimeException("图书已下架，无法借阅");
        }

        // 检查图书是否可借
        if (!bookService.isBookAvailable(bookId)) {
            throw new RuntimeException(ResultCode.BOOK_NOT_AVAILABLE.getMessage());
        }

        // 检查用户是否已借阅该图书
        if (hasUserBorrowedBook(userId, bookId)) {
            throw new RuntimeException("您已借阅该图书，无法重复借阅");
        }

        // 检查用户当前借阅数量
        Long currentBorrowCount = getUserCurrentBorrowCount(userId);
        if (currentBorrowCount >= maxBorrowBooks) {
            throw new RuntimeException("您当前借阅数量已达上限（" + maxBorrowBooks + "本）");
        }

        // 设置默认借阅天数
        if (borrowDays == null || borrowDays <= 0) {
            borrowDays = defaultBorrowDays;
        }

        // 创建借阅记录
        BorrowRecord borrowRecord = new BorrowRecord();
        borrowRecord.setUserId(userId);
        borrowRecord.setBookId(bookId);
        borrowRecord.setBorrowDate(LocalDateTime.now());
        borrowRecord.setDueDate(LocalDateTime.now().plusDays(borrowDays));
        borrowRecord.setStatus(BorrowRecord.STATUS_BORROWED);
        borrowRecord.setFineAmount(BigDecimal.ZERO);

        // 保存借阅记录
        if (!save(borrowRecord)) {
            throw new RuntimeException("借阅记录创建失败");
        }

        // 更新图书可借数量
        if (!bookService.borrowBook(bookId)) {
            throw new RuntimeException("图书库存更新失败");
        }

        System.out.println("用户" + userId + "成功借阅图书" + bookId + "，借阅记录ID：" + borrowRecord.getId());
        return borrowRecord;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean returnBook(Long recordId) {
        BorrowRecord borrowRecord = getById(recordId);
        if (borrowRecord == null) {
            throw new RuntimeException("借阅记录不存在");
        }

        // 检查借阅状态
        if (!borrowRecord.isBorrowed()) {
            throw new RuntimeException("该图书已归还或状态异常");
        }

        // 更新借阅记录
        borrowRecord.setReturnDate(LocalDateTime.now());
        borrowRecord.setStatus(BorrowRecord.STATUS_RETURNED);

        // 计算罚金（如果逾期）
        if (borrowRecord.isOverdue()) {
            long overdueDays = borrowRecord.getOverdueDays();
            BigDecimal fine = finePerDay.multiply(BigDecimal.valueOf(overdueDays));
            borrowRecord.setFineAmount(fine);
        }

        // 保存借阅记录
        if (!updateById(borrowRecord)) {
            throw new RuntimeException("借阅记录更新失败");
        }

        // 更新图书可借数量
        if (!bookService.returnBook(borrowRecord.getBookId())) {
            throw new RuntimeException("图书库存更新失败");
        }

        System.out.println("借阅记录" + recordId + "归还成功，罚金：" + borrowRecord.getFineAmount());
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean renewBook(Long recordId, Integer extendDays) {
        BorrowRecord borrowRecord = getById(recordId);
        if (borrowRecord == null) {
            throw new RuntimeException("借阅记录不存在");
        }

        // 检查借阅状态
        if (!borrowRecord.isBorrowed()) {
            throw new RuntimeException("该图书已归还或状态异常，无法续借");
        }

        // 检查是否逾期
        if (borrowRecord.isOverdue()) {
            throw new RuntimeException("图书已逾期，无法续借，请先归还");
        }

        // 设置默认续借天数
        if (extendDays == null || extendDays <= 0) {
            extendDays = defaultBorrowDays;
        }

        // 更新应还日期
        borrowRecord.setDueDate(borrowRecord.getDueDate().plusDays(extendDays));
        borrowRecord.setRemarks("续借" + extendDays + "天");

        boolean result = updateById(borrowRecord);
        if (result) {
            System.out.println("借阅记录" + recordId + "续借成功，续借" + extendDays + "天");
        }
        return result;
    }

    @Override
    public boolean hasUserBorrowedBook(Long userId, Long bookId) {
        return borrowRecordMapper.checkUserBookBorrow(userId, bookId) != null;
    }

    @Override
    public Long getUserCurrentBorrowCount(Long userId) {
        return borrowRecordMapper.countUserCurrentBorrow(userId);
    }

    @Override
    public Long getUserTotalBorrowCount(Long userId) {
        return borrowRecordMapper.countUserTotalBorrow(userId);
    }

    @Override
    public Long getBookBorrowCount(Long bookId) {
        return borrowRecordMapper.countBookBorrow(bookId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateOverdueStatus() {
        return borrowRecordMapper.updateOverdueStatus();
    }

    @Override
    public Object getBorrowStatistics() {
        Map<String, Object> statistics = new HashMap<>();

        // 总借阅记录数
        statistics.put("totalRecords", count());

        // 当前借出数量
        statistics.put("currentBorrowed", borrowRecordMapper.countBorrowRecords(BorrowRecord.STATUS_BORROWED, null, null));

        // 已归还数量
        statistics.put("totalReturned", borrowRecordMapper.countBorrowRecords(BorrowRecord.STATUS_RETURNED, null, null));

        // 逾期数量
        statistics.put("overdueCount", borrowRecordMapper.countBorrowRecords(BorrowRecord.STATUS_OVERDUE, null, null));

        // 今日借阅数量
        statistics.put("todayBorrow", borrowRecordMapper.countBorrowRecords(null, LocalDateTime.now().toLocalDate().atStartOfDay(), LocalDateTime.now()));

        // 今日归还数量
        statistics.put("todayReturn", borrowRecordMapper.countReturnRecords(LocalDateTime.now().toLocalDate(), LocalDateTime.now().toLocalDate()));

        // 借阅统计数据（最近7天）
        statistics.put("borrowTrend", borrowRecordMapper.getBorrowStatistics(LocalDateTime.now().minusDays(7), LocalDateTime.now()));

        return statistics;
    }

    @Override
    public List<Object> getPopularBooksStatistics(Integer limit) {
        List<Map<String, Object>> result = borrowRecordMapper.getPopularBooksStatistics(limit, null, null);
        return new ArrayList<>(result);
    }

    @Override
    public List<Object> getActiveUsersStatistics(Integer limit) {
        List<Map<String, Object>> result = borrowRecordMapper.getActiveUsersStatistics(limit, null, null);
        return new ArrayList<>(result);
    }

}